package common;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import math.LeastSquareMethod;
import math.common.MathCommon;
import math.probability.ExpDistribution;
import math.probability.LNormalDistribution;
import math.probability.LaplasDistribution;
import math.probability.NormalDistribution;
import math.probability.ProbDistribution;
import math.probability.UniformDistribution;

public class SampleTrimming {
	
	public Map<Double, Double> trimSample (final Map<Double, Double> smpl, final double p) {
		SortedMap<Double, Double> trimmedSmpl = new TreeMap<Double, Double> ();
		trimmedSmpl.putAll(smpl);
		int n = smpl.size();
		int k = (int) Math.round(n*p);
		
		for (int i = 0; i < k; i++ ) {
			Double first = trimmedSmpl.firstKey();
			Double last = trimmedSmpl.lastKey();
			trimmedSmpl.remove(first);
			trimmedSmpl.remove(last);
		
		}
		return trimmedSmpl;
	}
	
	public Map<Double, Double> trimSample1 (final Map<Double, Double> smpl, final double p) {
		SortedMap<Double, Double> trimmedSmpl = new TreeMap<Double, Double> ();
		trimmedSmpl.putAll(smpl);
		Double mean = MathCommon.getMean(new ArrayList(trimmedSmpl.keySet()));
		double min = (mean - trimmedSmpl.firstKey())*p;
		double max = (trimmedSmpl.lastKey() - mean)*p;
		
		
		for (Double u : smpl.keySet()) {
			if ((u < mean - min)||(u > mean + max))
				trimmedSmpl.remove(u);
			
		}
		return trimmedSmpl;
	}
	
	public void doWork () {
		double p = 0.2;
		double s = 0.5;
		int n = 100;
		int m = 1000;
//		ProbDistribution distX = new ExpDistribution(1/Math.sqrt(2.0));
		ProbDistribution distX = new UniformDistribution(0.0, 10.0);
//		ProbDistribution distX = new LNormalDistribution(0.0, 1.0);
		ProbDistribution distEps = new NormalDistribution(0.0,0.5);
		ProbDistribution distKsi = new NormalDistribution(0.0,s);
		Double b0 = 0.5;
		Double b1 = 1.0;
		StructuralModel model = new StructuralModel(n, distX, distKsi, distEps, b0,b1);
		
		Double b11 = 0.0;
		Double b12 = 0.0;
		
		for (int j=0; j<m; j++) {
			Map<Double, Double> data = model.getData();
			
			ArrayList<Double> V = new ArrayList<Double>(MathCommon.Normalize(data).values());
			ArrayList<Double> U = new ArrayList<Double>(MathCommon.Normalize(data).keySet());
			b11 += new LeastSquareMethod().estimate(V, U);
			
			Map<Double, Double> trimmedData = trimSample1(data, p);
			V = new ArrayList<Double>(MathCommon.Normalize(trimmedData).values());
			U = new ArrayList<Double>(MathCommon.Normalize(trimmedData).keySet());
			b12 += new LeastSquareMethod().estimate(V, U);
		}
		System.out.println(b11/m + ", " + b12/m);
	}
	
	public void doWork1() throws FileNotFoundException {
//		ProbDistribution distX = new ExpDistribution(1/Math.sqrt(2.0));
		ProbDistribution distX = new UniformDistribution(0.0, 10.0);
		ProbDistribution distEps = new NormalDistribution(0.0,0.5);
		ProbDistribution distXi = new NormalDistribution(0.0,1.0);
		int n = 100;
		double b0 = 0.5;
		double b1 = 1.0;
		
		List<Double> X = distX.getSample(n);
		List<Double> Eps = distEps.getSample(n);
		List<Double> Xi = distXi.getSample(n);
		
		List<Double> Y = new ArrayList<Double> ();
		for (Double x : X) {
			Y.add(b0+b1*x);
		}
		
		PrintWriter out = new PrintWriter (new FileOutputStream("data1.csv"));
		out.println("X,Y,Eps,Xi");
		for (int i=0; i<n; i++) {
			out.println(X.get(i)+","+Y.get(i)+","+Eps.get(i)+","+Xi.get(i));
		}
		out.flush();
		out.close();
		
	}
	
	private Map<Double, Double> getFun (ProbDistribution distX, ProbDistribution distEps,
			ProbDistribution distXi, int n, int m) {
		double b0 = 0.5;
		double b1 = 1.0;
		
		Map<Double, Double> B = new TreeMap<Double, Double> ();
		for (int i = 0; i < m; i++) {
			List<Double> X = distX.getSample(n);
			List<Double> Eps = distEps.getSample(n);
			List<Double> Xi = distXi.getSample(n);
			
			Map<Double, Double> V = new TreeMap<Double, Double> ();
			Map<Double, Double> normV = new TreeMap<Double, Double> ();			
			
			for (int j = 0; j < n; j++) {
				V.put(X.get(j)+Xi.get(j), b0+b1*X.get(j)+Eps.get(j));
			}
			
			Double meanU = MathCommon.getMean(new ArrayList<Double>(V.keySet()));
			Double meanV = MathCommon.getMean(new ArrayList<Double>(V.values()));
			for (Double u : V.keySet()) {
				normV.put(u-meanU, V.get(u)-meanV);
			}
			double p = 0.0;
			while (p < 0.35001) {
				if (B.get(p) == null) {
					B.put(p, 0.0);
				}
				Map<Double, Double> trV = trimSample(normV, p);
				B.put(p, B.get(p) + (double) new LeastSquareMethod().estimate(new ArrayList<Double>(trV.values()),
						new ArrayList<Double>(trV.keySet()))/m);
				p += 0.025;
			}
		}
		return B;
	}
	
	public void doWork2 () throws FileNotFoundException {

		
//		ProbDistribution distX = new UniformDistribution(0.0, 6.0);
		ProbDistribution distEps = new NormalDistribution(0.0,0.5);
		ProbDistribution distXi = new NormalDistribution(0.0,0.5);
		int n = 100;
		int m = 1000;
		
		ProbDistribution distX = new ExpDistribution(1/Math.sqrt(3.0));
		System.out.println(distX.getDisp());
		Map<Double, Double> B_Exp = getFun(distX, distEps, distXi, n, m);
		
		distX = new UniformDistribution(0.0, 6.0);
		System.out.println(distX.getDisp());
		Map<Double, Double> B_Un = getFun(distX, distEps, distXi, n, m);
		
		distX = new LNormalDistribution(-Math.log(4)/2.0, Math.log(4));
		System.out.println(distX.getDisp());
		Map<Double, Double> B_LN = getFun(distX, distEps, distXi, n, m);
		
		distX = new LaplasDistribution(Math.sqrt(2.0/3.0), 5.0);
		System.out.println(distX.getDisp());
		Map<Double, Double> B_L = getFun(distX, distEps, distXi, n, m);
		
		PrintWriter out = new PrintWriter (new FileOutputStream("TrimmedCoefs.csv"));
		out.println("p; b_Exp; b_Un; b_LN; B_L");
		for (Double p : B_Exp.keySet()) {
			out.println(p+";"+B_Exp.get(p)+";"+B_Un.get(p)+";"+B_LN.get(p)
					+";"+B_L.get(p));
		}
		out.flush();
		out.close();
		
	}
	
	public static void main (String[] args) throws FileNotFoundException {
		SampleTrimming st = new SampleTrimming();
		st.doWork2();
//		Double S1 = 0.0;
//		Double S2 = 0.0;
//		Double S3 = 0.0;
//		
//		for (int i=0; i<1000; i++) {
////		Random r = new Random();
//			S1 += MathCommon.getVar(new LNormalDistribution(-Math.log(4)/2.0, Math.log(4)).getSample(1000));
//			S2 += MathCommon.getVar(new ExpDistribution(1/Math.sqrt(3.0)).getSample(1000));
//			S3 += MathCommon.getVar(new UniformDistribution(0.0, 6.0).getSample(1000));
//		}
//		
//		System.out.println((double)S1/1000);
//		System.out.println((double)S2/1000);
//		System.out.println((double)S3/1000);
		
		
		
	}
}
